﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Platform.Linq;

namespace System.Linq
{
	public static class MapReduceExtensionMethods
	{

		/// <summary>
		/// Realiza o mapeamento dos dados
		/// </summary>
		/// <typeparam name="TInput"></typeparam>
		/// <typeparam name="TKey"></typeparam>
		/// <typeparam name="TEmit"></typeparam>
		/// <param name="elements"></param>
		/// <param name="emit"></param>
		/// <param name="keySelector"></param>
		/// <returns></returns>
		public static MapReduceQuery<TInput, TKey, TEmit> Map<TInput, TKey, TEmit>( this IQueryable<TInput> elements, Expression<Func<TInput, TEmit>> emit, Expression<Func<TEmit, TKey>> keySelector )
		{
			elements.HasOrderBy();

			//elements.Select( emit ).GroupBy( keySelector );
			//return new MapReduceQuery<TInput, TKey, TEmit>( elements, new MapReduceQueryProvider(), part => part.Select( emit ).GroupBy( keySelector ) );
			//return new MapReduceQuery<TInput, TKey, TEmit>( elements, new MapReduceQueryProvider(), new MapperFunction<TInput, TKey, TEmit>( emit, keySelector ) );
			return new MapReduceQuery<TInput, TKey, TEmit>( elements, elements.Provider, new MapperFunction<TInput, TKey, TEmit>( emit, keySelector ) );
		}

		public static MapReduceQuery<TInput, TKey, TEmit> MapNegative<TInput, TKey, TEmit>( this MapReduceQuery<TInput, TKey, TEmit> query )
		{
			query.Mapper.SetEmitNegated();
			return query;
		}

		/// <summary>
		/// Realiza o mapeamento dos dados que serão removidos do cojunto que já foi processado.
		/// </summary>
		/// <typeparam name="TInput"></typeparam>
		/// <typeparam name="TKey"></typeparam>
		/// <typeparam name="TEmit"></typeparam>
		/// <param name="query"></param>
		/// <param name="negativeEmitter"></param>
		/// <returns></returns>
		/// <remarks>Utilizado quando for feito updates parciais</remarks>
		public static MapReduceQuery<TInput, TKey, TEmit> MapNegative<TInput, TKey, TEmit>( this MapReduceQuery<TInput, TKey, TEmit> query, Expression<Func<TInput, TEmit>> negativeEmitter )
		{
			query.Mapper.SetEmitNegated( negativeEmitter );
			return query;
		}

		public static MapReduceQuery<TInput, TKey, TEmit> Reduce<TInput, TKey, TEmit>( this MapReduceQuery<TInput, TKey, TEmit> query, Expression<Func<IGrouping<TKey, TEmit>, TEmit>> reducer )
		{
			query.Reducer = new ReducerFunction<TKey, TEmit>( reducer );
			return query;
		}

		private static void HasOrderBy<TElement>( this IQueryable<TElement> elements )
		{
			// TODO: A clausula "OrderBy" é utilizada para definir até em que ponto os dados foram processados
		}

		internal static void RemoveCompleteTasks( this List<Task> tasks )
		{
			for ( int index = tasks.Count - 1; index >= 0; index-- )
				if ( tasks[ index ].IsCompleted )
					tasks.RemoveAt( index );
		}

		internal static void WaitAll( this List<Task> tasks )
		{
			if ( tasks.Count > 0 )
				Task.WaitAll( tasks.ToArray() );
		}
	}

}
